home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / EMSIF230.ARJ / EMSIF.DOC next >
Text File  |  1991-12-01  |  53KB  |  1,162 lines

  1.                                  EMSIF
  2.           Version-independent C Interface to LIM EMS Functions
  3.                   for LIM EMS versions 3.0 and higher
  4.                            EMSIF version 2.3
  5.                           by James W. Birdsall
  6.                                 12/01/91
  7.  
  8.  
  9. 0. CONTENTS
  10. -----------
  11.  
  12.    0.     CONTENTS
  13.    I.     INTRODUCTION
  14.     I.1    WHAT IS SUPPORTED
  15.     I.2    COPYRIGHT, LICENSE, AND WARRANTY DISCLAIMER
  16.    II.    COMPILING AND LINKING WITH THE LIBRARIES
  17.     II.1   WITH C
  18.     II.2   WITH C++
  19.     II.3   EMSTEST, THE EXAMPLE PROGRAM
  20.    III.   PROGRAMMING WITH EMSIF
  21.     III.1  INITIALIZING THE LIBRARY
  22.     III.2  ORDINARY USE
  23.     III.3  FRAME CACHING
  24.     III.4  SAVE/RESTORE
  25.     III.5  OTHER TIPS
  26.     III.6  FUNCTION GROUPING
  27.    IV.    LIBRARY REFERENCE
  28.     IV.1   GLOBAL VARIABLES
  29.     IV.2   FUNCTIONS
  30.    V.     ERROR CODES
  31.     V.1    INTERNAL ERRORS
  32.     V.2    EMS DRIVER ERRORS
  33.    VI.    THE END
  34.     VI.1   ACKNOWLEDGEMENTS
  35.  
  36.  
  37. I. INTRODUCTION
  38. ---------------
  39.  
  40.    EMSIF provides a high-level interface to LIM EMS control functions
  41. for common operations such as allocating, mapping, and freeing EMS, and
  42. copying data to and from EMS. The interface has been made independent of
  43. the EMS version implemented by the EMS driver as far as possible, so
  44. that parameters and returned data are always in the same format, but the
  45. EMS call most appropriate to the EMS version implemented by the driver
  46. is used.
  47.  
  48.    EMSIF is written in assembly language for speed and assembled with
  49. Borland's Turbo Assembler (TASM) 2.5. The source code is not compatible
  50. with the Microsoft Assembler (MASM).
  51.  
  52.  I.1 WHAT IS SUPPORTED
  53.  ---------------------
  54.  
  55.    EMSIF expressly supports the Lotus-Intel-Microsoft (LIM) Expanded
  56. Memory Specification (EMS) versions 3.0, 3.2, and 4.0. Versions above
  57. 4.0 are supported as 4.0. Versions below 3.0 are not supported.
  58. Save/restore is not supported under version 3.0, and assigning names to
  59. EMS handles is only supported under version 4.0. These exceptions to
  60. version-independence are due to limitations of the unsupported versions;
  61. the necessary services are not available from the driver.
  62.  
  63.    EMSIF supports tiny, small, medium, compact, large, and huge memory
  64. models. The small model library supports both tiny and small models, so
  65. no library is provided specifically for tiny model.
  66.  
  67.    EMSIF supports any version of Turbo C, Turbo C++, or Borland C++, in
  68. both C and C++ modes, and Microsoft C 6.00 and 6.00A. EMSIF has been
  69. tested with Borland C++ 2.0, Turbo C 2.0, and Microsoft C 6.00A in all
  70. of the supported memory models. EMSIF should work with earlier versions
  71. of Microsoft C and any other C compiler that 1) uses compatible
  72. parameter passing and return methods and 2) can use standard-format
  73. libraries.
  74.  
  75.  I.2 COPYRIGHT, LICENSE, AND WARRANTY DISCLAIMER
  76.  -----------------------------------------------
  77.  
  78.    EMSIF is not in the public domain. All the files are copyright 1991
  79. by James W. Birdsall, all rights reserved. Permission is granted to do
  80. the following:
  81.  
  82.         You may freely redistribute this archive, so long as it contains
  83.         all the files listed in the file MANIFEST, intact and
  84.         unmodified.
  85.  
  86.         You may use the libraries in programs for your own use. You may
  87.         not distribute programs linked with these libraries.
  88.  
  89.    Payment of the $5 shareware registration fee ($50 for commercial use)
  90. grants the following license, in addition to the permissions listed
  91. above:
  92.  
  93.         You may request the source to EMSIF. You may modify the source
  94.         as necessary for use in your programs. However, you may not
  95.         redistribute either the original or modified source.
  96.  
  97.         You may distribute programs linked with either the original
  98.         libraries or libraries generated from source you have modified,
  99.         without royalty, provided you (a) do not alter or remove
  100.         copyright notices contained therein and (b) you indemnify, hold
  101.         harmless, and defend the author from and against any claims or
  102.         lawsuits, including attorney's fees, that arise or result from
  103.         the use or distribution of your software product. 
  104.  
  105. For the purposes of this license, commercial use is defined as use by an
  106. incorporated entity in a software product that is regarded as the
  107. product of the corporation, no matter how the software product is
  108. distributed, but only if 100 or more copies of the product are expected
  109. to be made.
  110.  
  111.    The contents of the distribution archive, and all other related
  112. files, information, and services are provided "as is" and without
  113. warranty. To the extent permitted by applicable law, the author
  114. disclaims all warranties, express or implied, including but not limited
  115. to, any implied warranty of merchantability or fitness for a particular
  116. purpose. While effort has been made to ensure that the files, information,
  117. and services are accurate and correct, the author shall not be liable
  118. for damages arising out of the use of or inability to use this product,
  119. including but not limited to, loss of profit, data, or use of this
  120. software, or special, incidental, or consequential damages or other
  121. similar claims, even if the author has been specifically advised of the
  122. possibility of such damages. Some states do not allow the exclusion of
  123. incidental or consequential damages, so the foregoing limitation may not
  124. apply to you.
  125.  
  126.    Information on contacting the author is provided at the end of this
  127. file.
  128.  
  129.  
  130. II. COMPILING AND LINKING WITH THE LIBRARIES
  131. --------------------------------------------
  132.  
  133.    This section describes how to use the EMSIF libraries with your
  134. programs.
  135.  
  136.    EMSIF is provided as Borland/Microsoft standard library files.
  137. Libraries are provided for small, medium, compact, large, and huge
  138. memory models (tiny model uses the small model library). The model for
  139. which a library is intended is indicated by the last letter of the
  140. filename proper, which is the same as the first letter for the model.
  141. For example, EMSIFL.LIB is the large model library.
  142.  
  143.  II.1 WITH C
  144.  -----------
  145.  
  146.    To use EMSIF in C programs, you must #include the file EMSIF.H in
  147. every source file that calls EMSIF functions, accesses EMSIF global
  148. variables, or uses #defined constants provided by EMSIF.
  149.  
  150.    The procedures for linking EMSIF with the rest of your program vary
  151. according to the compiler and method you are using. In general, you must
  152. include the appropriate library (the library corresponding to the memory
  153. model in which you have compiled the rest of your program) in the link.
  154.  
  155.    If you are compiling in the Integrated Development Environment of
  156. Turbo/Borland C[++], you should include the name of the appropriate
  157. library in the project file for your program. For example, if you are
  158. working in the compact memory model, you should include EMSIFC.LIB in
  159. your project file.
  160.  
  161.    If you are using a command-line compiler (bcc, tcc, or cl) to compile
  162. and link, simply place the full name of the appropriate EMSIF library on
  163. the command line. For example, "bcc -mc foo.c emsifc.lib" will compile
  164. the file "foo.c" in the compact model and link it with emsifc.lib.
  165.  
  166.    If you are linking manually (using TLINK or LINK), place the name of
  167. the appropriate library in with the other libraries. For example,
  168.         tlink c0c.obj foo.obj, foo.exe, foo.map, cc.lib emsifc.lib
  169. or
  170.         link foo.obj, foo.exe, foo.map, emsifc.lib ;
  171. will link the object "foo.obj" with the appropriate startup object and
  172. standard library (LINK automatically includes the startup object and
  173. standard library, so it is not necessary to explicitly include them) and
  174. the compact model EMSIF library.
  175.  
  176.  II.2 C++
  177.  --------
  178.  
  179.    To use EMSIF in C++ programs, you must #include the file EMSIF.HPP in
  180. every file that calls EMSIF functions, accesses EMSIF global variables,
  181. or uses #defined constants provided by EMSIF. Be careful to include
  182. EMSIF.HPP instead of EMSIF.H. If you include the wrong one, you will
  183. probably see "undefined symbol" errors when linking.
  184.  
  185.    Otherwise, the procedures for using EMSIF with C++ programs are the
  186. same as for using it with C programs.
  187.  
  188.  II.3 EMSTEST, THE EXAMPLE PROGRAM
  189.  ---------------------------------
  190.  
  191.    A large and complete example program and tester, EMSTEST, has been
  192. included in this distribution. It can be compiled in any of the
  193. supported memory models (although tiny model requires some contortions
  194. to do so), with either Borland or Microsoft compilers.
  195.  
  196.    The test program has four source files: EMSTEST.C, EMSTEST2.C,
  197. EMSTEST3.C, and TESTUTIL.C, and two header files: EMSTEST.H and
  198. TESTUTIL.H. When compiling in tiny model with Borland compilers, an
  199. additional source file, STACK.ASM, is needed. STACK.OBJ, which is
  200. STACK.ASM pre-assembled, has been included for those who do not have
  201. assemblers.
  202.  
  203.    Example makefiles have been included for Borland and Microsoft
  204. compilers. EXMAKEBC is the example makefile for Borland C++ 2.0,
  205. EXMAKETC is the example makefile for Turbo C[++], and EXMAKEMS is the
  206. example makefile for Microsoft C. Complete instructions for making the
  207. example program and using the example makefiles are included at the
  208. beginning of each makefile. More information about the program is also
  209. included at the beginning of EMSTEST.C.
  210.  
  211.    EMSTEST requires at least eight pages of available expanded memory
  212. and at least 190,000 bytes of available conventional memory to run.
  213.  
  214.  
  215. III. PROGRAMMING WITH EMSIF
  216. ----------------------------
  217.  
  218.    This section describes how to make EMSIF calls in your program, and
  219. details various tricks and tips which you may find useful.
  220.  
  221.  III.1 INITIALIZATION
  222.  --------------------
  223.  
  224.    The library initialization function EMMlibinit() _must_ be called
  225. before any other EMSIF calls are made. All other EMSIF functions are
  226. guaranteed to fail if called before EMMlibinit(). EMMlibinit()
  227. determines whether an EMS driver is present and sets up various internal
  228. and global variables necessary to the functioning of EMSIF.
  229.  
  230.  III.2 ORDINARY USE
  231.  ------------------
  232.  
  233.    EMSIF provides several sets of functions. First, there is a set of
  234. functions which are intended to be orthogonal with the standard C
  235. functions malloc() and free(), and the Borland/Turbo C[++] function
  236. coreleft(). These functions are EMMalloc(), EMMfree(), and
  237. EMMcoreleft().
  238.  
  239.    Second, there is a group of functions for copying data to and from
  240. expanded memory. These functions allow you to treat allocated blocks of
  241. expanded memory pages as linear memory, hiding the details of page
  242. mapping. These functions are EMMcopyto(), EMMcopyfrom(), EMMicopyto(),
  243. EMMicopyfrom(), _EMMicopyto(), and _EMMicopyfrom().
  244.  
  245.    Third, there is a group of low-level functions which allow more
  246. direct access to EMS driver calls. These functions are EMMallocpages(),
  247. EMMgetframeaddr(), EMMgetnumframe(), EMMgetsinfraddr(), and
  248. EMMmappage(). With these functions it is possible to duplicate the
  249. copying functions or access expanded memory in other ways. Calls to
  250. these functions can be mixed with calls to copying functions without
  251. trouble.
  252.  
  253.    Fourth, there is a group of miscellaneous functions: EMMgetname(),
  254. EMMsetname(), EMMgetversion(), EMMsave(), and EMMrestore().
  255.  
  256.    Finally, there is a group of functions which affect only the
  257. operation of EMSIF itself: _EMMenc(), _EMMdisc(), _EMMinval(),
  258. EMMlibinit(), and EMMsrinit(). For details on all the functions listed
  259. above, see section IV.2.
  260.  
  261.    To use expanded memory, first it is necessary to allocate some. This
  262. can be done with either EMMalloc(), which takes a size in bytes, or
  263. EMMallocpages(), which allocates EMS pages directly. Both return a
  264. handle which will be used to reference the allocated memory.
  265.  
  266.    To access the expanded memory, you can either use the copying
  267. functions, or access it directly. The copying functions are pretty
  268. self-explanatory. Accessing expanded memory directly is more
  269. complicated. First, it is necessary to determine the addresses of the
  270. EMS page frames. EMS page frames 0 through 3 are available under all EMS
  271. versions and are intended for general use. While EMS version 4.0
  272. provides additional page frames, they are intended for use by
  273. multitaskers such as Quarterdeck DesqView and Microsoft Windows. These
  274. additional page frames may appear anywhere, even in the middle of your
  275. program. Use them only with great caution. To obtain the addresses of
  276. all page frames, use EMMgetframeaddr(). To obtain the address of a
  277. single page frame, use EMMgetsinfraddr(). The addresses returned by both
  278. these functions are segment addresses and must be converted to far
  279. pointers before actually being used.
  280.  
  281.    Having decided which page frame or frames you wish to use, and
  282. determined the necessary addresses, it is then necessary to map EMS
  283. logical pages into the page frame(s). This is accomplished with
  284. EMMmappage(). Once this is done, you can then access any byte in that
  285. logical page (which is 16384 bytes long) using the far pointer created
  286. earlier. Mapping a logical page into a page frame into which a
  287. logical page has already been mapped causes the original logical page to
  288. be displaced by the new logical page. A logical page may be mapped in
  289. any number of times (although having one mapped into multiple page
  290. frames simultaneously may cause unexpected results), and a page frame
  291. can have logical pages mapped into it any number of times (but only the
  292. last one mapped into a given page frame is accessible in that page
  293. frame).
  294.  
  295.    The miscellaneous functions listed above allow you to determine the
  296. EMS version supported by the driver (EMMgetversion()), to associate a
  297. string name with an EMS handle and retrieve the name associated with an
  298. EMS handle (EMMsetname()/EMMgetname()), and save and restore EMS page
  299. mappings (EMMsave()/EMMrestore()). More information on the last is
  300. available in section III.4.
  301.  
  302.    The internal functions _EMMenc(), _EMMdisc(), and _EMMinval() are
  303. discussed in section III.3 below. EMMlibinit() has already been
  304. discussed, in section III.1, and EMMsrinit() is discussed in section
  305. III.4 below.
  306.  
  307.    Many functions return a status directly. For those functions, a
  308. return value of 0 indicates success and a return value of EMMOOPS
  309. indicates failure. The global variable _EMMerror contains an error code
  310. which gives further information on why the function failed, or has value
  311. 0 if the function succeeded. Many functions return some other value
  312. instead of a status code (0 or EMMOOPS). In these cases, the value of
  313. _EMMerror should be checked upon return. The recommended method of
  314. error-checking is indicated for each function in section IV.2 below.
  315.  
  316.  III.3 FRAME CACHING
  317.  -------------------
  318.  
  319.    EMSIF uses a technique called "frame caching" to speed up the copying
  320. functions. It keeps track of the handle and page number of the logical
  321. page currently mapped into page frame 2. When starting a copy, EMSIF
  322. calculates the handle and logical page needed, and if that page is
  323. already mapped into page frame 2, does not perform a mapping call. This
  324. technique can greatly increase the copying speed, especially if many
  325. separate copies to the same page are being performed.
  326.  
  327.    Frame caching is on by default. To check the current setting, inspect
  328. the global variable _EMMframecache. If it is nonzero, frame caching is
  329. on; if it is 0, frame caching is off. The state of frame caching is
  330. changed via the functions _EMMenc() (enable caching) and _EMMdisc()
  331. (disable caching).
  332.  
  333.    Frame caching has one unfortunate weakness. It assumes that all EMS
  334. mapping activity will be performed via EMSIF, so that an accurate record
  335. of the contents of frame 2 can be kept. If you are using another
  336. third-party library that also uses EMS, then obviously there is mapping
  337. activity that is not performed via EMSIF, and frame caching will cause
  338. the copying functions to malfunction.
  339.  
  340.    This is why _EMMenc() and _EMMdisc() were created. If you have this
  341. problem, you have a number of options:
  342.  
  343.         1) You can disable frame caching globally. Just call _EMMdisc()
  344.            somewhere between the EMMlibinit() call and the first call to
  345.            an EMSIF copying function. If you mostly do large copies,
  346.            especially copies which cross page boundaries, then there
  347.            will be almost no performance loss. If you do lots of
  348.            separate copies to the same page, performance may drop by up
  349.            to 50% or more. In that case, you should probably pick
  350.            another option.
  351.  
  352.         2) You can disable frame caching around calls to the other
  353.            library. If the calls to the other library occur in clusters,
  354.            you can call _EMMdisc() before the cluster and _EMMenc()
  355.            after. Alternatively, if the calls to EMSIF form more
  356.            convenient clusters, you can call _EMMenc() before and
  357.            _EMMdisc() after. Note that _EMMdisc() sets a flag which
  358.            invalidates the current cache contents, so that when caching
  359.            is re-enabled EMSIF does not become confused.
  360.  
  361.         3) If calls to the other library are sparse, you can simply
  362.            invalidate the cache each time you make a call to the other
  363.            library, using the macro _EMMinval(). It does not matter
  364.            whether you call _EMMinval() before or after the call to the
  365.            other library, as long as the cache is invalidated before the
  366.            next EMSIF copying call is made.
  367.  
  368.  III.4 SAVE/RESTORE
  369.  ------------------
  370.  
  371.    Worse interactions with other libraries can occur. If the other
  372. library assumes that the EMS mapping will not change between calls to
  373. it, then almost any EMSIF activity at all will interfere with the other
  374. library. This is why save/restore capability was added to EMSIF. Note
  375. that save/restore only works with EMS version 3.2 and up. While EMS
  376. version 3.0 claimed to have save/restore capability, it is so radically
  377. different from that in versions 3.2 and up that it cannot be
  378. consolidated under the same interface. If you use save/restore in your
  379. program, you give up compatibility with EMS version 3.0.
  380.  
  381.    The EMS specification (for versions 3.2 and up) includes calls to
  382. save the current EMS mapping to a buffer in memory, and restore a
  383. mapping from such a buffer. EMSIF's save/restore function are an
  384. interface to these calls. Before any save/restore calls can be made,
  385. EMMsrinit() must be called to initialize save/restore. It takes a single
  386. parameter, which is a pointer to a function used to allocate save
  387. buffers. Malloc() may be passed in any memory model, but any other
  388. function with the same prototype may be used. Note that the passed
  389. function will never be required to allocate more that 255 bytes in one
  390. call.
  391.  
  392.    Having initialized save/restore, you can call EMMsave() to save a
  393. mapping and EMMrestore() to restore one. The pointer returned by
  394. EMMsave() is the value returned by an internal call to the function
  395. which was passed to EMMsrinit(), and may be freed when necessary with
  396. whatever function would ordinarily be called; for example, if malloc()
  397. was passed to EMMsrinit(), then pointers returned by EMMsave() may be
  398. passed to free(). Note that EMMrestore() does not free save buffers. You
  399. must free them yourself.
  400.  
  401.    To avoid interference with libraries that assume that the EMS mapping
  402. will not change, simply call EMMsave() after calls to that library, and
  403. call EMMrestore() with the pointer returned by the last EMMsave() before
  404. the next call to that library. Note that EMMrestore() invalidates the
  405. frame cache. In fact, if you have to use save/restore in this way, it
  406. would probably be best to disable frame caching globally, perhaps
  407. enabling it around loops which perform lots of copies if you really need
  408. the performance boost.
  409.  
  410.    Save/restore can also be used to quickly alternate between several
  411. complex mappings. Having established a mapping, save it with EMMsave().
  412. Then, when you need it again, a call to EMMrestore() will restore it
  413. quickly and easily. A given mapping may be restored from the same buffer
  414. any number of times.
  415.  
  416.  III.5 OTHER TIPS
  417.  ----------------
  418.  
  419.    Expanded memory is not deallocated automatically when a program
  420. exits. If the program does not deallocate expanded memory it has
  421. allocated, that expanded memory is stuck, not available to any other
  422. program until the machine is rebooted. Under normal circumstances, it is
  423. easy enough to free expanded memory when it is no longer needed.
  424. However, an emergency exit due to the user hitting control-break or due
  425. to a hardware error (e.g. the famous "Abort, Retry, Fail?") can cause
  426. expanded memory to become stuck unless your program takes special
  427. measures to intercept these errors and perform cleanup before exiting.
  428. There are a number of ways to do this and they vary from compiler to
  429. compiler. Look for functions named things like ctrlbrk(), harderr() and
  430. signal().
  431.  
  432.    If you are copying array elements, _EMMicopyto()/_EMMicopyfrom() or
  433. EMMicopyto()/EMMicopyfrom() may be more efficient. These functions allow
  434. copying of elements of fixed size which are separated by gaps also of
  435. fixed size. For example, if you have an array of integers and wish to
  436. copy all the even-indexed elements (a[0], a[2], a[4], etc.), these
  437. functions are far faster than calling a standard copying function
  438. (EMMcopyto() or EMMcopyfrom()) from within a loop. While the performance
  439. improvement varies from machine to machine, the smallest speed increase
  440. that I have seen is seven times, ranging up to over twenty times on a
  441. fast machine with frame caching off.
  442.  
  443.  III.6 FUNCTION GROUPING
  444.  -----------------------
  445.  
  446.    The EMSIF functions have been arranged in the library in such a way
  447. as to reduce the number of unnecessary functions linked into your
  448. program. There are currently five groups:
  449.  
  450.                 FUNCTIONS                               VARIABLES
  451.                 ---------                               ---------
  452. GROUP 1:        EMMlibinit(), EMMgetversion(),          _EMMerror, _EMMversion,
  453.                 EMMgetnumframe(), EMMgetsinfraddr(),    _EMMframecache,
  454.                 EMMgetframeaddr(), EMMmappage()         emsif_vers_vers,
  455.                                                         emsif_vers_date,
  456.                                                         emsif_vers_time
  457.  
  458. GROUP 2:        EMMcoreleft(), EMMallocpages(),         none
  459.                 EMMalloc(), EMMfree()
  460.  
  461. GROUP 3:        EMMcopyto(), EMMcopyfrom(),             none
  462.                 _EMMicopyto(), _EMMicopyfrom(),
  463.                 _EMMenc(), _EMMdisc()
  464.  
  465. GROUP 4:        EMMsrinit(), EMMsave(), EMMrestore()    none
  466.  
  467. GROUP 5:        EMMgetname(), EMMsetname()              none
  468.  
  469. If your program references any of the functions or variables in a group,
  470. all the functions and variables in that group will be linked in. Note
  471. that group one will always be linked, since it contains EMMlibinit(),
  472. which all EMSIF-using programs must call.
  473.  
  474.  
  475. IV. LIBRARY REFERENCE
  476. ---------------------
  477.  
  478.  IV.1 GLOBAL VARIABLES
  479.  ---------------------
  480.  
  481.   _EMMerror
  482.   ---------
  483.  
  484.    unsigned char const _EMMerror;
  485.  
  486.    _EMMerror contains the error code from the last EMSIF call. If the
  487. call succeeded, _EMMerror will be 0. If the call failed because the EMS
  488. driver returned an error, _EMMerror contains the error code returned by
  489. the EMS driver. If the call failed because EMSIF detected an error
  490. internally, _EMMerror contains an intenal error code. A list of error
  491. code values, their meanings, and #defined constants for them is in
  492. section V.
  493.  
  494.   _EMMframecache
  495.   --------------
  496.  
  497.    unsigned char const _EMMframecache;
  498.  
  499.    _EMMframecache is a flag which indicates whether frame caching is
  500. enabled or not. A nonzero value indicates that frame caching is enabled,
  501. and 0 indicates that frame caching is disabled. See section IV.3 for a
  502. discussion of frame caching.
  503.  
  504.   _EMMversion
  505.   -----------
  506.  
  507.    unsigned char const _EMMversion;
  508.  
  509.    _EMMversion contains the EMS version implemented by the EMS driver in
  510. packed BCD format. For example, if the EMS version is 4.0, the value of
  511. _EMMversion will be 0x40. If _EMMversion is 0x32, the EMS version is
  512. 3.2. This value is the same as that returned by EMMgetversion().
  513.  
  514.   emsif_vers_vers, emsif_vers_date, emsif_vers_time
  515.   -------------------------------------------------
  516.  
  517.    char const emsif_vers_vers[];
  518.    char const emsif_vers_date[];
  519.    char const emsif_vers_time[];
  520.  
  521.    These are null-terminated strings containing information about the
  522. name and version of the library, the date of assembly, and the time of
  523. assembly, respectively.
  524.  
  525.  IV.2 FUNCTIONS
  526.  --------------
  527.  
  528.   _EMMdisc() - disable frame caching
  529.   ----------
  530.  
  531.    void _EMMdisc(void);
  532.    void _EMMenc(void);
  533.    void _EMMinval(void);
  534.  
  535.    _EMMdisc() disables frame caching, invalidates the current cache
  536. contents, and sets _EMMframecache to zero. _EMMerror should be checked
  537. after calling this function. It is not an error to call this function
  538. when frame caching is already disabled.
  539.  
  540.    _EMMenc() enables frame caching, invalidates the current cache
  541. contents, and sets _EMMframecache to a nonzero value. _EMMerror should
  542. be checked after calling this function. It is not an error to call this
  543. function when frame caching is already enabled; however, the current
  544. cache contents will still be invalidated.
  545.  
  546.    _EMMinval() is a macro that invalidates the current cache contents if
  547. frame caching is enabled, or has no effect if frame caching is disabled.
  548. The frame caching status is not changed. _EMMerror should be checked
  549. afterwards.
  550.  
  551.    For more information on frame caching, see section III.3.
  552.  
  553.   _EMMenc() - enable frame caching
  554.   ---------
  555.  
  556.    void _EMMenc(void);
  557.  
  558.    See _EMMdisc();
  559.  
  560.   _EMMicopyfrom() - copy data by intervals from EMS
  561.   ---------------
  562.  
  563.    int _EMMicopyfrom(unsigned long nelem, int elsize,
  564.                      unsigned int srcskip, int handle, unsigned long foffset,
  565.                      unsigned char far *dest, unsigned int destskip);
  566.    int _EMMicopyto(unsigned long nelem, int elsize,
  567.                    unsigned int srcskip, unsigned char far *source,
  568.                    int handle, unsigned long foffset, unsigned int destskip);
  569.  
  570.    _EMMicopyfrom() allows painless copying of array elements from
  571. expanded memory to conventional memory. EMS mapping, calculation of
  572. addresses, skipping of unwanted elements, etc., are all handled by the
  573. function. Elements spread across more than 64K, or totalling more than
  574. 64K in length, can be copied without special treatment.
  575.    Nelem elements are copied, each of which is elsize bytes long. The
  576. elements are copied from the EMS pages owned by handle, starting at byte
  577. offset foffset and with srcskip bytes between elements, to conventional
  578. memory starting at dest with destskip bytes between elements. Dest must
  579. be a far pointer; a near pointer can be converted to a far pointer with
  580. a cast when the function is called. Byte offsets in EMS are as for
  581. EMMcopyfrom().
  582.    If nelem or elsize is zero, the function returns immediately without
  583. error. Elsize must be in the range 0 through 16384, or the function will
  584. return with error EMM_ELTOOBIG (in _EMMerror). Byteskip must be in the
  585. range 0 through 32768, or the function will return with error
  586. EMM_SKTOOBIG.
  587.    This function returns 0 on success or EMMOOPS on error. The specific
  588. error may be determined from _EMMerror.
  589.  
  590.    _EMMicopyto() allows painless copying of array elements from
  591. conventional memory to expanded memory. EMS mapping, calculation of
  592. addresses, skipping of unwanted elements, etc., are all handled by the
  593. function. Elements spread across more than 64K, or totalling more than
  594. 64K in length, can be copied without special treatment.
  595.    Nelem elements are copied, each of which is elsize bytes long. The
  596. elements are copied from conventional memory starting at source with
  597. srcskip bytes between elements, to the EMS pages owned by handle, starting
  598. at byte offset foffset and with destskip bytes between elements. Source
  599. must be a far pointer; a near pointer can be converted to a far pointer
  600. with a cast when the function is called. Byte offsets in EMS are as for
  601. EMMcopyto().
  602.    If nelem or elsize is zero, the function returns immediately without
  603. error. Elsize must be in the range 0 through 16384, or the function will
  604. return with error EMM_ELTOOBIG (in _EMMerror). Byteskip must be in the
  605. range 0 through 32768, or the function will return with error
  606. EMM_SKTOOBIG.
  607.    This function returns 0 on success or EMMOOPS on error. The specific
  608. error may be determined from _EMMerror.
  609.  
  610.   _EMMicopyto() - copy data by intervals to EMS
  611.   -------------
  612.  
  613.    int _EMMicopyto(unsigned long nelem, int elsize,
  614.                    unsigned int srcskip, unsigned char far *source,
  615.                    int handle, unsigned long foffset, unsigned int destskip);
  616.  
  617.  
  618.    See _EMMicopyfrom().
  619.  
  620.   _EMMinval() - invalidate frame cache contents
  621.   -----------
  622.  
  623.    void _EMMinval(void);
  624.  
  625.    See _EMMdisc().
  626.  
  627.   EMMalloc() - allocate EMS
  628.   ----------
  629.  
  630.    int EMMalloc(unsigned long bytes);
  631.    int EMMallocpages(int pages);
  632.  
  633.    EMMalloc() allocates EMS memory. It takes the given number of bytes
  634. and allocates the smallest number of pages which contain that many
  635. bytes. It returns the EMS handle assigned by the EMS driver. _EMMerror
  636. should be checked after calling this function.
  637.    Note that EMS cannot be allocated in units smaller than a page (16384
  638. bytes). Requesting one byte will allocate a whole page; 16385 bytes will
  639. allocate two pages. Requesting zero bytes allocates one page.
  640.  
  641.    EMMallocpages() allocates EMS memory by pages directly. It returns
  642. the EMS handle assigned by the EMS driver. _EMMerror should be checked
  643. after calling this function. It is possible to allocate 0 pages with
  644. this function, but only under EMS version 4.0; under earlier versions,
  645. allocating 0 pages is an error.
  646.  
  647.   EMMallocpages() - allocate EMS by pages
  648.   ---------------
  649.  
  650.    int EMMallocpages(int pages);
  651.  
  652.    See EMMalloc().
  653.  
  654.   EMMcopyfrom() - copy data from EMS
  655.   -------------
  656.  
  657.    int EMMcopyfrom(unsigned long copylen,
  658.                    int handle, unsigned long foffset,
  659.                    unsigned char far *dest);
  660.    int EMMcopyto(unsigned long copylen,
  661.                  unsigned char far *source,
  662.                  int handle, unsigned long foffset);
  663.  
  664.    EMMcopyfrom() allows painless copying of blocks of data from expanded
  665. memory to conventional memory. All mapping, calculation of addresses,
  666. etc., is handled by the function. Copies longer than 64K are possible
  667. without special treatment.
  668.    Copylen bytes of data are copied, from the EMS pages owned by handle,
  669. starting at byte offset foffset, to the conventional memory area pointed
  670. to by dest. Dest must be a far pointer; a near pointer can be converted
  671. to a far pointer with a cast when the function is called. To convert an
  672. expanded memory offset (such as foffset) to a page and offset within
  673. that page, divide the offset by the size of a page (16384 bytes). The
  674. quotient is the page number and the remainder is the offset within that
  675. page. Offsets 0 through 16383 are in page 0; offsets 16384 through 32767
  676. are in page 1, etc. This feature allows you to treat expanded memory
  677. blocks as linear memory rather than a collection of pages.
  678.    This function returns 0 on success or EMMOOPS on error. The specific
  679. error may be determined from _EMMerror. If copylen is 0, the function
  680. returns immediately without error.
  681.  
  682.    EMMcopyto() is the mirror image of EMMcopyfrom(). It allows painless
  683. copying of blocks of data from conventional memory to expanded memory.
  684. All mapping, calculation of addresses, etc., is handled by the function.
  685. Copies longer than 64K are possible without special treatment.
  686.    Copylen bytes of data are copied, from the conventional memory area
  687. pointed to by source, to the EMS pages owned by handle, starting at
  688. byte offset foffset. Expanded memory offsets are as in EMMcopyfrom().
  689.    This function returns 0 on success or EMMOOPS on error. The specific
  690. error may be determined from _EMMerror. If copylen is 0, the function
  691. returns immediately without error.
  692.  
  693.    See also EMMicopyto() and EMMicopyfrom().
  694.  
  695.   EMMcopyto() - copy data to EMS
  696.   -----------
  697.  
  698.    int EMMcopyto(unsigned long copylen,
  699.                  unsigned char far *source,
  700.                  int handle, unsigned long foffset);
  701.  
  702.    See EMMcopyfrom().
  703.  
  704.   EMMcoreleft() - get amount of free EMS
  705.   -------------
  706.  
  707.    unsigned long EMMcoreleft(void);
  708.  
  709.    This function returns the amount of EMS memory available, in bytes.
  710. To determine the number of EMS pages available, divide the returned
  711. value by 16384. _EMMerror should be checked after calling this function.
  712.  
  713.   EMMfree() - deallocate EMS
  714.   ---------
  715.  
  716.    int EMMfree(int handle);
  717.  
  718.    This function accepts an EMS handle (as returned by EMMalloc() or
  719. EMMallocpages(), or otherwise obtained from the EMS driver) and releases
  720. it and any EMS pages allocated to it. This function returns 0 on success
  721. or EMMOOPS on error. The specific error may be determined from
  722. _EMMerror.
  723.  
  724.   EMMgetframeaddr() - get EMS page frame segment addresses
  725.   -----------------
  726.  
  727.    int EMMgetframeaddr(frameinfo *buffer);
  728.    int EMMgetnumframe(void);
  729.    unsigned int EMMgetsinfraddr(int frame);
  730.  
  731.    EMMgetframeaddr() returns the segment addresses of all the EMS page
  732. frames. Buffer is a pointer to an array of frameinfo structures; this
  733. array is assumed to be large enough to contain information about all the
  734. frames. The number of frameinfo structures needed can be determined with
  735. the EMMgetnumframe() function described below.
  736.    Each frameinfo structure contains the number and the segment address
  737. of a frame. Check EMSIF.H or EMSIF.HPP for the exact format of the
  738. frameinfo structure. The information is returned in whatever order the
  739. EMS driver provides it, which is typically sorted by address rather than
  740. frame number. Do NOT just assume that the first element in the array
  741. contains information for frame 0! The segment addresses returned must be
  742. converted to far pointers (using MK_FP() or your compiler's equivalent)
  743. before they can be used to access memory.
  744.    This function returns 0 on success or EMMOOPS on error. The specific
  745. error may be determined from _EMMerror.
  746.  
  747.    EMMgetnumframe() returns the number of EMS page frames present in the
  748. system. For EMS versions below 4.0, this will always be 4. For EMS
  749. version 4.0, it will be at least 4. _EMMerror should be checked after
  750. calling this function.
  751.  
  752.    EMMgetsinfraddr() returns the segment address of a particular EMS
  753. page frame. This address must be converted to a far pointer (using
  754. MK_FP() or your compiler's eqivalent) before it can be used to access
  755. memory.
  756.    Note that this function calls EMMgetframeaddr() internally and
  757. allocates a temporary buffer for it on the stack. Therefore, depending
  758. on how many page frames the system has, this function may require many
  759. bytes of stack space.
  760.    _EMMerror should be checked after calling this function.
  761.  
  762.   EMMgetname() - obtain string name associated with an EMS handle
  763.   ------------
  764.  
  765.    int EMMgetname(int handle, char *name);
  766.    int EMMsetname(int handle, char *name);
  767.  
  768.    EMMgetname() returns (as a null-terminated string) the name, if any,
  769. assigned to an EMS handle. Real names are only implemented in EMS
  770. version 4.0. Under earlier versions, this function fills the name buffer
  771. with nulls ('\0'), which is also the return under version 4.0 when no
  772. name has been associated with the given handle. The buffer pointed to by
  773. name must be at least nine characters long (since an EMS name may be up
  774. to eight characters long and there must be room for a terminating null).
  775. This function returns 0 on success or EMMOOPS on error. The specific
  776. error may be determined from _EMMerror.
  777.  
  778.    EMMsetname() allows the association of a name up to eight characters
  779. long with an EMS handle. It only works for EMS version 4.0; under
  780. earlier versions, it returns the error EMM_BADVERS. Version independence
  781. has been abandoned in this case because the main purpose of associating
  782. a name with an EMS handle is to allow several different programs to
  783. recognize shared data. While EMSIF could implement a naming function
  784. within itself, the names would not be visible outside the program
  785. assigning the name, defeating the purpose of doing so in the first
  786. place. This function returns 0 on success or EMMOOPS on error. The
  787. specific error may be determined from _EMMerror.
  788.  
  789.   EMMgetnumframe() - obtain number of EMS page frames
  790.   ----------------
  791.  
  792.    int EMMgetnumframe(void);
  793.  
  794.    See EMMgetframeaddr().
  795.  
  796.   EMMgetsinfraddr() - get segment address of one EMS page frame
  797.   -----------------
  798.  
  799.    unsigned int EMMgetsinfraddr(int frame);
  800.  
  801.    See EMMgetframeaddr().
  802.  
  803.   EMMgetversion() - obtain EMS version implemented by EMS driver
  804.   ---------------
  805.  
  806.    int EMMgetversion(void);
  807.  
  808.    This function returns the EMS version implemented by the EMS driver.
  809. The version number is in packed BCD format as in the global variable
  810. _EMMversion, and is in fact the same value. _EMMerror should be checked
  811. after calling this function.
  812.  
  813.   EMMicopyfrom() - copy data by intervals from EMS
  814.   --------------
  815.  
  816.    int EMMicopyfrom(unsigned long nelem, int elsize, unsigned int byteskip,
  817.                     int handle, unsigned long foffset,
  818.                     unsigned char far *dest);
  819.    int EMMicopyto(unsigned long nelem, int elsize, unsigned int byteskip,
  820.                   unsigned char far *source,
  821.                   int handle, unsigned long foffset);
  822.  
  823.    EMMicopyfrom() is a macro which calls _EMMicopyfrom(). It allows
  824. painless copying of array elements from expanded memory to conventional
  825. memory. EMS mapping, calculation of addresses, skipping of unwanted
  826. elements, etc., are all handled by the function. Elements spread across
  827. more than 64K, or totalling more than 64K in length, can be copied without
  828. special treatment.
  829.    Nelem elements are copied, each of which is elsize bytes long, with
  830. byteskip bytes between elements at both source and destination. The
  831. elements are copied from the EMS pages owned by handle, starting at byte
  832. offset foffset, to conventional memory starting at dest. Dest must be a
  833. far pointer; a near pointer can be converted to a far pointer with a cast
  834. when the function is called. Byte offsets in EMS are as for EMMcopyfrom().
  835.    If nelem or elsize is zero, the function returns immediately without
  836. error. Elsize must be in the range 0 through 16384, or the function will
  837. return with error EMM_ELTOOBIG (in _EMMerror). Byteskip must be in the
  838. range 0 through 32768, or the function will return with error
  839. EMM_SKTOOBIG.
  840.    This function returns 0 on success or EMMOOPS on error. The specific
  841. error may be determined from _EMMerror.
  842.  
  843.    EMMicopyto() is a macro which calls _EMMicopyto(). It allows painless
  844. copying of array elements from conventional memory to expanded memory.
  845. EMS mapping, calculation of addresses, skipping of unwanted elements,
  846. etc., are all handled by the function. Elements spread across more than
  847. 64K, or totalling more than 64K in length, can be copied without special
  848. treatment.
  849.    Nelem elements are copied, each of which is elsize bytes long, with
  850. byteskip bytes between elements at both source and destination. The elements
  851. are copied from conventional memory starting at source, to the EMS pages
  852. owned by handle, starting at byte offset foffset. Source must be a far
  853. pointer; a near pointer can be converted to a far pointer with a cast when
  854. the function is called. Byte offsets in EMS are as for EMMcopyto().
  855.    If nelem or elsize is zero, the function returns immediately without
  856. error. Elsize must be in the range 0 through 16384, or the function will
  857. return with error EMM_ELTOOBIG (in _EMMerror). Byteskip must be in the
  858. range 0 through 32768, or the function will return with error
  859. EMM_SKTOOBIG.
  860.    This function returns 0 on success or EMMOOPS on error. The specific
  861. error may be determined from _EMMerror.
  862.  
  863.   EMMicopyto() - copy data by intervals to EMS
  864.   ------------
  865.  
  866.    int EMMicopyto(unsigned long nelem, int elsize, unsigned int byteskip,
  867.                   unsigned char far *source,
  868.                   int handle, unsigned long foffset);
  869.  
  870.    See EMMicopyfrom().
  871.  
  872.   EMMlibinit() - initialize EMSIF
  873.   ------------
  874.  
  875.    int EMMlibinit(void);
  876.  
  877.    EMMlibinit() initializes EMSIF. Any other EMSIF function will return
  878. with error EMM_NOINIT (in _EMMerror) if called before EMMlibinit() has
  879. been called. This function returns 0 on success, EMMOOPS on error, or
  880. NOEMM if no EMS driver is detected. The specific error may be determined
  881. from _EMMerror. Note that EMSIF will not initialize if the EMS driver
  882. claims that fewer than four EMS page frames exist, since that is a
  883. violation of the EMS specification and the driver may have other
  884. anomalies that EMSIF does not know how to handle.
  885.    Detection of the EMS driver relies on DOS services, so this library
  886. cannot be used in a device driver as it stands. If you need this library
  887. for a device driver or other program that cannot access DOS services,
  888. you can buy the source (it's cheap) and easily modify EMMlibinit() to
  889. use another method of detection. There are no other calls to DOS
  890. services in EMSIF. The method used was chosen for its reliability;
  891. there is another method, suitable for use in device drivers, which is
  892. not as reliable and typically is useful _only_ for device drivers.
  893.  
  894.   EMMmappage() - map an EMS logical page into an EMS page frame
  895.   ------------
  896.  
  897.    int EMMmappage(int frameno, int handle, int logpage);
  898.  
  899.    This function maps a logical page into an EMS page frame so that it
  900. can be accessed. The logical page logpage belonging to handle is mapped
  901. into page frame number frameno. This function returns 0 on success or
  902. EMMOOPS on error. The specific error may be determined from _EMMerror.
  903.  
  904.   EMMrestore() - restore an EMS mapping from a save buffer
  905.   ------------
  906.  
  907.    int EMMrestore(void *saveblock);
  908.    void *EMMsave(void);
  909.    int EMMsrinit(void *(*mallocfunc)(size_t));
  910.  
  911.    EMMrestore() restores an EMS mapping that has earlier been saved in a
  912. save buffer with a call to EMMsave(). The contents of the frame cache
  913. are invalidated, since the format of the contents of the save buffer
  914. varies from one EMS driver to the next and it is thus not possible to
  915. determine what will be mapped into the cached frame when the restore is
  916. done. EMMrestore() does not deallocate the save buffer.
  917.    This function returns 0 on success or EMMOOPS on error. The specific
  918. error may be determined from _EMMerror. It is an error if this function
  919. is called before EMMsrinit() has been called.
  920.  
  921.    EMMsave() allocates a save buffer (see EMMsrinit(), below) and saves
  922. the current EMS mapping into it. The current EMS mapping is not changed,
  923. nor are the contents of the frame cache invalidated. This function
  924. returns the pointer returned by the allocation function (see below).
  925.    _EMMerror should be checked after calling this function. It is an
  926. error if this function is called before EMMsrinit() has been called.
  927.  
  928.    EMMsrinit() initializes the save/restore capability of EMSIF. It
  929. takes a pointer to a memory-allocation function which is used by
  930. EMMsave() to allocate save buffers. Malloc() is compatible in all memory
  931. models, but any function which works the same way (returns a void
  932. pointer of the size normal for the memory model (near or far), takes a
  933. single parameter of type size_t which is the number of bytes to
  934. allocate, and returns NULL (0) if the memory cannot be allocated) can
  935. also be used. Note that the function will never be required to allocate
  936. more than 255 bytes in one call
  937.    EMMsrinit() will fail to initialize and return EMM_BADVERS if the EMS
  938. version is 3.0. Since it did not initialize, EMMsave() and EMMrestore()
  939. will not work either.
  940.    _EMMerror should be checked after calling this function.
  941.  
  942.    For more information on frame caching and suggestions on using
  943. save/restore, see sections III.3 and III.4 respectively.
  944.  
  945.   EMMsave() - save an EMS mapping into a save buffer
  946.   ---------
  947.  
  948.    void *EMMsave(void);
  949.  
  950.    See EMMrestore().
  951.  
  952.   EMMsetname() - associate string name with an EMS handle
  953.   ------------
  954.  
  955.    int EMMsetname(int handle, char *name);
  956.  
  957.    See EMMgetname().
  958.  
  959.   EMMsrinit() - initialize save/restore
  960.   -----------
  961.  
  962.    int EMMsrinit(void *(*mallocfunc)(size_t));
  963.  
  964.    See EMMrestore().
  965.  
  966.  
  967. V. ERROR CODES
  968. --------------
  969.  
  970.    This section is a list of the error codes to which the global variable
  971. _EMMerror may be set, and the values and meanings thereof.
  972.  
  973.  V.1 INTERNAL ERRORS
  974.  -------------------
  975.  
  976.    Internal codes indicate an error detected by EMSIF itself.
  977.  
  978.    NAME                 VALUE     MEANING
  979.    ----                 -----     -------
  980.    EMM_BADVERS           0x40     Bad EMS version, earlier than 3.0.
  981.  
  982.    EMM_BADOFFSET         0x41     Offset plus copy length runs off last
  983.                                   EMS page owned by handle.
  984.  
  985.    EMM_NOFRAME           0x42     Could not find segment address of page frame
  986.                                   used for copying functions (frame 2).
  987.  
  988.    EMM_NOINIT            0x43     EMMlibinit() must be called before any
  989.                                   other EMSIF function can be called.
  990.  
  991.    EMM_FEWFRAMES         0x44     The EMS driver claims that there are fewer
  992.                                   than four page frames.
  993.  
  994.    EMM_NOSR              0x45     EMMsrinit() must be called before
  995.                                   EMMsave() or EMMrestore() can be called.
  996.  
  997.    EMM_MEMNULL           0x46     The save/restore memory allocation
  998.                                   function (the one passed to EMMsrinit())
  999.                                   returned NULL.
  1000.  
  1001.    EMM_ELTOOBIG          0x47     The element size passed to EMMicopyto()
  1002.                                   or EMMicopyfrom() is too big.
  1003.  
  1004.    EMM_SKTOOBIG          0x48     The skip size passed to EMMicopyto()
  1005.                                   or EMMicopyfrom() is too big.
  1006.  
  1007.  V.2 EMS DRIVER ERRORS
  1008.  ---------------------
  1009.  
  1010.    These codes are defined in the EMS specification and are returned by
  1011. the EMS driver. They are saved in _EMMerror by EMSIF without alteration.
  1012.  
  1013.    NAME                 VALUE     MEANING
  1014.    ----                 -----     -------
  1015.    EMM_SOFTERROR         0x80     Internal error exists in EMS driver (can
  1016.                                   indicate corrupted memory image of driver)
  1017.  
  1018.    EMM_HARDERROR         0x81     Malfunction in expanded memory hardware
  1019.  
  1020.    EMM_BUSY              0x82     EMS driver is busy
  1021.  
  1022.    EMM_BADHANDLE         0x83     Invalid EMS handle
  1023.  
  1024.    EMM_UNIMP             0x84     Function not defined
  1025.  
  1026.    EMM_NOFREEHAN         0x85     No free EMS handles
  1027.  
  1028.    EMM_CONTEXTERR        0x86     Error in save or restore of mapping context
  1029.  
  1030.    EMM_WAYTOOBIG         0x87     Tried to allocate more pages than physically
  1031.                                   exist in system; no pages allocated
  1032.  
  1033.    EMM_TOOBIG            0x88     Tried to allocate more pages than currently
  1034.                                   available; no pages allocated
  1035.  
  1036.    EMM_TOOSMALL          0x89     Cannot allocate 0 pages
  1037.  
  1038.    EMM_BADLOGPAGE        0x8A     Requested logical page is outside range of
  1039.                                   pages owned by handle
  1040.  
  1041.    EMM_BADFRAMENO        0x8B     Illegal frame number in mapping request
  1042.  
  1043.    EMM_HSTATESAVFULL     0x8C     Page-mapping hardware-state save area full
  1044.  
  1045.    EMM_MSTATESAVFULL     0x8D     Mapping-context save failed; save area
  1046.                                   already contains context associated with
  1047.                                   specified handle
  1048.  
  1049.    EMM_MSTATERESTERR     0x8E     Mapping-context restore failed; save area
  1050.                                   does not contain context for specified
  1051.                                   handle
  1052.  
  1053.    EMM_UNIMPSUB          0x8F     Subfunction parameter not defined
  1054.  
  1055.    EMM_BADATTRIB         0x90     Attribute type not defined
  1056.  
  1057.    EMM_NOFEATURE         0x91     Feature not supported
  1058.  
  1059.    EMM_SRCOVERWRITE      0x92     Source and destination memory regions have
  1060.                                   same handle and overlap; requested move
  1061.                                   was performed, but part of the source region
  1062.                                   was overwritten
  1063.  
  1064.    EMM_BADLENGTH         0x93     Copy length longer than actual length
  1065.  
  1066.    EMM_CONEMSOVERLAP     0x94     Conventional memory region and expanded
  1067.                                   memory region overlap
  1068.  
  1069.    EMM_OFFPAGE           0x95     Specified offset outside logical page
  1070.  
  1071.    EMM_TOOLONG           0x96     Copy length exceeds one megabyte
  1072.  
  1073.    EMM_EMSEMSOVERLAP     0x97     Source and destination memory regions have
  1074.                                   same handle and overlap; exchange cannot be
  1075.                                   performed
  1076.  
  1077.    EMM_LOST              0x98     Memory source and destination types
  1078.                                   undefined
  1079.  
  1080.    EMM_UNUSED            0x99     This error code is currently unused
  1081.  
  1082.    EMM_BADALTREG         0x9A     Alternate map or DMA register sets are
  1083.                                   supported, but specified alternate register
  1084.                                   set is not supported
  1085.  
  1086.    EMM_NOFREEALTREG      0x9B     Alternate map or DMA register sets are
  1087.                                   supported, but all alternate register sets
  1088.                                   are currently allocated
  1089.  
  1090.    EMM_NOALTREG          0x9C     Alternate map or DMA register sets are not
  1091.                                   supported, specified alternate register
  1092.                                   set is not 0
  1093.  
  1094.    EMM_BADALTREG2        0x9D     Alternate map or DMA register sets are
  1095.                                   supported, but the alternate register set
  1096.                                   specified is not defined or not allocated
  1097.  
  1098.    EMM_NODEDDMA          0x9E     Dedicated DMA channels are not supported
  1099.  
  1100.    EMM_BADDEDDMA         0x9F     Dedicated DMA channels are supported, but
  1101.                                   specified DMA channel is not supported
  1102.  
  1103.    EMM_UNKNAME           0xA0     Handle for specified name not found
  1104.  
  1105.    EMM_NAMETAKEN         0xA1     Handle with same name already exists
  1106.  
  1107.    EMM_ADDRWRAP          0xA2     Memory address wraps; sum of source or
  1108.                                   destination region base address and length
  1109.                                   exceeds one megabyte
  1110.  
  1111.    EMM_BADPTR            0xA3     Invalid pointer passed to function, or
  1112.                                   contents of source array corrupted
  1113.  
  1114.    EMM_FORBIDDENFUNC     0xA4     Access to function denied by operating
  1115.                                   system
  1116.  
  1117. VI. THE END
  1118. -----------
  1119.  
  1120.    Technical support via email is available from the following addresses:
  1121.  
  1122.    INTERNET:
  1123.       First choice (the following are alternate addresses for the same place):
  1124.          support@picarefy.com
  1125.          picarefy!support@amc.com
  1126.          picarefy!support@netcom.com
  1127.          picarefy!support@halcyon.com
  1128.          amc-gw!picarefy!support@coco.ms.washington.edu
  1129.          halcyon!picarefy!support@sumax.seattleu.edu
  1130.          uunet!uw-coco!amc-gw!picarefy!support
  1131.  
  1132.       Second choice:
  1133.          jwbirdsa@amc.com
  1134.  
  1135.    COMPUSERVE:
  1136.       71261,1731
  1137.  
  1138.    AMERICA ON-LINE:
  1139.       GreenTiger
  1140.  
  1141.    GENIE:
  1142.       J.BIRDSALL2
  1143.  
  1144.    Registrations should be sent to:
  1145.  
  1146.       James W. Birdsall
  1147.       11112 NE 124 LN #D204
  1148.       Kirkland, WA 98034
  1149.  
  1150.    If you have an email address on any of the networks listed above,
  1151. please include it when registering, especially if you are requesting
  1152. source code. It is much easier to send the source code by email. Also,
  1153. please specify what sort of archive (ZIP, ZOO, ARC, LZH, ARJ, UNIX shar)
  1154. you can handle most easily.
  1155.  
  1156.  VI.1 ACKNOWLEDGEMENTS
  1157.  ---------------------
  1158.  
  1159.    Thanks to Bob Parsons of Parsons Technology Inc. for some good suggestions
  1160. on the documentation and for providing the original C++ header file.
  1161.  
  1162.